#ifndef AFCORE_COMMON_LOG_APPENDER_APPENDER_CONSOLE_COLOR_ANSI_
#define AFCORE_COMMON_LOG_APPENDER_APPENDER_CONSOLE_COLOR_ANSI_

#include <memory>
#include <array>
#include <string>

#include "logcommon.h"
#include "helper.h"
#include "appender.h"

namespace afcore {

/// @brief  日志
namespace log {

template<typename ConsoleMutex>
class CAppenderAnsicolor
  : public CNocopyable
  , public CAppender {
public:
  // Formatting codes
  const RStringView reset = "\033[m";
  const RStringView bold = "\033[1m";
  const RStringView dark = "\033[2m";
  const RStringView underline = "\033[4m";
  const RStringView blink = "\033[5m";
  const RStringView reverse = "\033[7m";
  const RStringView concealed = "\033[8m";
  const RStringView clear_line = "\033[K";

  // Foreground colors
  const RStringView black = "\033[30m";
  const RStringView red = "\033[31m";
  const RStringView green = "\033[32m";
  const RStringView yellow = "\033[33m";
  const RStringView blue = "\033[34m";
  const RStringView magenta = "\033[35m";
  const RStringView cyan = "\033[36m";
  const RStringView white = "\033[37m";

  /// Background colors
  const RStringView on_black = "\033[40m";
  const RStringView on_red = "\033[41m";
  const RStringView on_green = "\033[42m";
  const RStringView on_yellow = "\033[43m";
  const RStringView on_blue = "\033[44m";
  const RStringView on_magenta = "\033[45m";
  const RStringView on_cyan = "\033[46m";
  const RStringView on_white = "\033[47m";

  /// Bold colors
  const RStringView yellow_bold = "\033[33m\033[1m";
  const RStringView red_bold = "\033[31m\033[1m";
  const RStringView bold_on_red = "\033[1m\033[41m";

  CAppenderAnsicolor(FILE* file, EAppenderColorMode mode);
  ~CAppenderAnsicolor() override = default;

  /// @brief  对应日志级别设置颜色
  /// @param  l               日志级别
  /// @param  color           颜色
  void SetColor(ELogLevel l, RStringView color);
  /// @brief  记录
  /// @param  msg         日志信息
  void Log(const SLogMessage& msg) final override;
  /// @brief  刷新
  void Flush() final override;
  /// @brief  设置模式
  /// @param  pattern    模式
  void SetPattern(const std::string& pattern) final override;
  /// @brief  设置格式
  /// @param  formatter   格式
  void SetFormatter(RFormatterUptr formatter) final override;
  /// @brief  设置颜色模式
  /// @param  mode            颜色模式
  void SetColorMode(EAppenderColorMode mode);
  /// @brief  是否需要颜色
  /// @return 颜色标志
  bool ShouldColor();
protected:
  /// @brief  打印颜色编码
  /// @param  color_code  颜色编码
  void PrintColorCode(const RStringView& color_code);
  /// @brief  根绝范围打印颜色
  /// @param  formatted   格式化后的数据
  /// @param  start       颜色开始位置
  /// @param  end         颜色结束位置
  void PrintRange(const RMemoryBuf& formatted, size_t start, size_t end);

protected:
  using RMutex = typename ConsoleMutex::RMutex;
  FILE* file_;
  RMutex& mutex_;                                       ///< 互斥锁
  bool should_do_colors_ {false};                       ///< 是否需要颜色
  RFormatterUptr formatter_;                            ///< 格式记录器
  std::array<RStringView , kLogLevelEnable> colors_;    ///< 日志级别对应的颜色
};

template<typename ConsoleMutex>
class CAppenderAnsicolorStdout
  : public CAppenderAnsicolor<ConsoleMutex> {
public:
  explicit CAppenderAnsicolorStdout(EAppenderColorMode mode = EAppenderColorMode::kAppenderColorMode_Automatic);
};

template<typename ConsoleMutex>
class CAppenderAnsicolorStderr
  : public CAppenderAnsicolor<ConsoleMutex> {
public:
  explicit CAppenderAnsicolorStderr(EAppenderColorMode mode = EAppenderColorMode::kAppenderColorMode_Automatic);
};

using RAppenderAnsicolorStdout_MT = CAppenderAnsicolorStdout<SConsoleMutex>;
using RAppenderAnsicolorStdout_ST = CAppenderAnsicolorStdout<SConsoleNullMutex>;

using RAppenderAnsicolorStderr_MT = CAppenderAnsicolorStderr<SConsoleMutex>;
using RAppenderAnsicolorStderr_ST = CAppenderAnsicolorStderr<SConsoleNullMutex>;

} // !namespace log

} // !namespace afcore

#endif //! AFCORE_COMMON_LOG_APPENDER_APPENDER_CONSOLE_COLOR_ANSI_